package jmine.tec.aom.domain.impl;

import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Transient;

import jmine.tec.aom.AOMMessages;
import jmine.tec.aom.domain.AbstractPropertyValue;
import jmine.tec.aom.domain.EnumProperty;
import jmine.tec.aom.exception.FillException;
import jmine.tec.persist.annotation.DiscriminatorComment;
import bancosys.tec.component.Documentation;
import bancosys.tec.persist.dao.BaseDAO;

/**
 * {@link AbstractPropertyValue} implementation for {@link Enum} types.
 * 
 * @author jrenaut
 */
@Entity
@DiscriminatorValue("15")
@DiscriminatorComment("ENUM")
public class EnumPropertyValue extends AbstractPropertyValue<Enum> {

    private Integer ordinal;

    /**
     * @return the ordinal
     */
    @Column(name = "VL_INTEGER")
    @Documentation("VALOR DA CARACTERISTICA DO TIPO INTEGER")
    public Integer getOrdinal() {
        return this.ordinal;
    }

    /**
     * @param ordinal the ordinal to set
     */
    public void setOrdinal(Integer ordinal) {
        this.ordinal = ordinal;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Transient
    public Enum getValue() {
        if (this.ordinal == null) {
            return null;
        }
        return this.findEnumClass().getEnumConstants()[this.ordinal];
    }

    /**
     * @return the actual enum class {@link Class}
     */
    private Class<? extends Enum> findEnumClass() {
        BaseDAO<EnumProperty> dao = this.getController().getDAOFactory().getGenericDAO(EnumProperty.class);
        EnumProperty p = dao.narrow(this.getProperty());
        try {
            return p.getEnumType();
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException("The required enum class was not found for property " + this.getPropertyName(), e);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setValue(Enum value) {
        if (value == null) {
            this.ordinal = null;
        } else {
            if (!value.getClass().equals(this.findEnumClass())) {
                throw new IllegalArgumentException("Illegal attempt to set a value of type " + value.getClass().getCanonicalName()
                        + " on property " + this.getPropertyName() + " which expects type " + this.findEnumClass().getCanonicalName());
            }
            this.ordinal = value.ordinal();
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public void doSetValue(String stringValue) throws FillException {
        try {
            this.ordinal = Enum.valueOf(this.findEnumClass(), stringValue).ordinal();
        } catch (IllegalArgumentException e) {
            throw new FillException(AOMMessages.INVALID_ENUM_VALUE.create(this.getPropertyName(), stringValue));
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected AbstractPropertyValue<Enum> createBean() {
        EnumPropertyValue bean = (EnumPropertyValue) super.createBean();
        bean.setOrdinal(this.getOrdinal());
        return bean;
    }

}
